//this is a module that stores the values of hash
//Last modified by yangjao at 2021/5/13

module HRAM(
    input wire clk,
    input wire rst_n,
    input wire reset,
    input wire update,
    input wire select,
    input wire[31:0] in1,
    input wire[31:0] in2,
    input wire[31:0] in3,
    input wire[31:0] in4,
    input wire[31:0] in5,
    input wire[31:0] in6,
    input wire[31:0] in7,
    input wire[31:0] in8,

    output reg hash_Valid,
    output wire[7:0] data_out,
    output wire[31:0] out1,
    output wire[31:0] out2,
    output wire[31:0] out3,
    output wire[31:0] out4,
    output wire[31:0] out5,
    output wire[31:0] out6,
    output wire[31:0] out7,
    output wire[31:0] out8
);

//the origin value of hash //sha256
parameter H0_sha256_A = 32'h6a09e667;
parameter H0_sha256_B = 32'hbb67ae85;
parameter H0_sha256_C = 32'h3c6ef372;
parameter H0_sha256_D = 32'ha54ff53a;
parameter H0_sha256_E = 32'h510e527f;
parameter H0_sha256_F = 32'h9b05688c;
parameter H0_sha256_G = 32'h1f83d9ab;
parameter H0_sha256_H = 32'h5be0cd19;

//the origin value of hash //sm3
parameter H0_sm3_A = 32'h7380166f;
parameter H0_sm3_B = 32'h4914b2b9;
parameter H0_sm3_C = 32'h172442d7;
parameter H0_sm3_D = 32'hda8a0600;
parameter H0_sm3_E = 32'ha96f30bc;
parameter H0_sm3_F = 32'h163138aa;
parameter H0_sm3_G = 32'he38dee4d;
parameter H0_sm3_H = 32'hb0fb0e4e;

reg[31:0] HASH [0:7];
reg[31:0] data_out_pre;
reg[4:0] addr;

assign out1 = HASH[0];
assign out2 = HASH[1];
assign out3 = HASH[2];
assign out4 = HASH[3];
assign out5 = HASH[4];
assign out6 = HASH[5];
assign out7 = HASH[6];
assign out8 = HASH[7];

assign data_out = data_out_pre[7:0];

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        HASH[0] <= H0_sha256_A;
        HASH[1] <= H0_sha256_B;
        HASH[2] <= H0_sha256_C;
        HASH[3] <= H0_sha256_D;
        HASH[4] <= H0_sha256_E;
        HASH[5] <= H0_sha256_F;
        HASH[6] <= H0_sha256_G;
        HASH[7] <= H0_sha256_H;
    end else if(reset && select) begin
        HASH[0] <= H0_sm3_A;
        HASH[1] <= H0_sm3_B;
        HASH[2] <= H0_sm3_C;
        HASH[3] <= H0_sm3_D;
        HASH[4] <= H0_sm3_E;
        HASH[5] <= H0_sm3_F;
        HASH[6] <= H0_sm3_G;
        HASH[7] <= H0_sm3_H;
    end else if(reset && !select) begin
        HASH[0] <= H0_sha256_A;
        HASH[1] <= H0_sha256_B;
        HASH[2] <= H0_sha256_C;
        HASH[3] <= H0_sha256_D;
        HASH[4] <= H0_sha256_E;
        HASH[5] <= H0_sha256_F;
        HASH[6] <= H0_sha256_G;
        HASH[7] <= H0_sha256_H;
    end else if(update) begin
        HASH[0] <= in1;
        HASH[1] <= in2;
        HASH[2] <= in3;
        HASH[3] <= in4;
        HASH[4] <= in5;
        HASH[5] <= in6;
        HASH[6] <= in7;
        HASH[7] <= in8;
    end
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        hash_Valid <= 0;
    end else if(update)begin
        hash_Valid <= 1;
    end else if(&addr)begin
        hash_Valid <= 0;
    end
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        addr <= 5'b0;
    end else if(hash_Valid)begin
        addr <= addr + 1;
    end else begin
        addr <= 5'b0;
    end
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        data_out_pre <= 32'b0;
    end else if(!addr[1] && !addr[0])begin
        data_out_pre <= HASH[addr[4:2]];
    end else begin
        data_out_pre <= data_out_pre >> 8;
    end
end

endmodule
